package testjava;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.SortedMap;
import java.util.TreeMap;

public class TestZip {

    public static void main(String[] args) throws Exception {
        addSameFile("test.apk", "", "replace");
    }

    static void addSameFile(String source, String target, String files) throws IOException {
        TreeMap<Integer, CentralDirectoryHeader> indexTree = new TreeMap<Integer, CentralDirectoryHeader>();
        CentralDirectoryEnd end = getCenterEnd(source);
        CentralDirectoryHeader[] index = getCenterIndex(source, end.offset, end.total);
        BufferedReader br = new BufferedReader(new FileReader(files));
        String file = br.readLine();
        while (null != file) {
            String trim = file.trim();
            if (trim.length() != 0) {
                for (int i = 0; i < index.length; i++) {
                    if (Arrays.equals(trim.getBytes(), index[i].name)) {
                        indexTree.put(index[i].offset, index[i]);
                        break;
                    }
                }
            }
            file = br.readLine();
        }
        br.close();
    }

    static void replaceIcon() throws IOException {
        String path = "icon.zip";
        new File(path).delete();
        ZipCompressor zipCompressor = new ZipCompressor(path);
        zipCompressor.compress("icon.png", "res/drawable-hdpi/");
        zipCompressor.close();
        CentralDirectoryEnd iconEnd = getCenterEnd(path);
        CentralDirectoryHeader[] index = getCenterIndex(path, iconEnd.offset, iconEnd.number);
        CentralDirectoryHeader newicon = index[0];
        path = "test.apk";
        CentralDirectoryEnd apkEnd = getCenterEnd(path);
        index = getCenterIndex(path, apkEnd.offset, apkEnd.number);
        int oldSize = 0;
        int pos = -1;
        for (int i = 0; i < index.length; i++) {
            if (Arrays.equals(newicon.name, index[i].name)) {
                oldSize = index[i].getSize();
                pos = i;
                break;
            }
        }
        short cLength = (short) 0x8000;
        System.out.println(cLength + "-" + pos);
        File target = new File("test.apk.zip");
        target.delete();
        FileOutputStream fos = new FileOutputStream(target);
        FileInputStream fis = new FileInputStream(path);
        FileInputStream iconIn = new FileInputStream("icon.zip");
        readWrite(fis, fos, apkEnd.offset);
        readWrite(iconIn, fos, iconEnd.offset);
        for (int i = 0; i < index.length; i++) {
            if (i == pos - 1) {
                index[i].extraLength = cLength;
                index[i].writeTo(fos);
            } else if (pos == i) {
                int j = Endian.toUnsign(cLength) - index[i].getSize();
                index[i].extraLength = (short) newicon.getSize();
                index[i].commentLength = (short) j;
                index[i].writeTo(fos);
                newicon.offset = apkEnd.offset;
                newicon.writeTo(fos);
            } else {
                index[i].writeTo(fos);
            }
        }
        apkEnd.offset += iconEnd.offset;
        apkEnd.cdSize += newicon.getSize() + Endian.toUnsign(cLength) - oldSize;
        apkEnd.writeTo(fos);

        iconIn.close();
        fis.close();
        fos.close();
    }

    private static CentralDirectoryEnd getCenterEnd(String path) throws IOException {
        EndianInputStream in = new EndianInputStream(new FileInputStream(path));
        in.skip(in.available() - CentralDirectoryEnd.MIN_LEN);
        CentralDirectoryEnd end = new CentralDirectoryEnd(in);
        in.close();
        return end;
    }

    private static CentralDirectoryHeader[] getCenterIndex(String path, int offset, int count) throws IOException {
        EndianInputStream in = new EndianInputStream(new FileInputStream(path));
        in.skip(offset);
        CentralDirectoryHeader[] headers = new CentralDirectoryHeader[count];
        for (int i = 0; i < count; i++) {
            CentralDirectoryHeader header = new CentralDirectoryHeader(in);
            headers[i] = header;
        }
        in.close();
        return headers;
    }

    private static void tZip(String path) throws IOException {

        EndianInputStream in = new EndianInputStream(new FileInputStream(path));
        System.out.println("SIGNATURE\tVN2E\tFLAG\tMETHOD\tTIME\tDATE\tCRC32\tCSIZE\tUSIZE\tNAME");
        while (true) {
            int sig = in.readInt();
            if (0x04034b50 != sig) break;
            System.out.print(Integer.toHexString(sig) + "\t");
            System.out.print(in.readShort() + "\t"); // vn2e
            short flag = in.readShort();
            System.out.print(flag + "\t"); // flag
            System.out.print(in.readShort() + "\t"); // method
            // System.out.print(new Date(in.readInt()) + "\t");
            System.out.print(in.readShort() + "\t"); // time
            System.out.print(in.readShort() + "\t"); // date
            System.out.print(in.readInt() + "\t"); // crc32
            int csize = in.readInt();
            System.out.print(csize + "\t"); // csize
            System.out.print(in.readInt() + "\t"); // usize
            int nameLength = in.readUnsignedShort();
            int extraLength = in.readShort();
            byte[] buffer = new byte[nameLength];
            in.read(buffer);
            System.out.print(nameLength + new String(buffer) + extraLength + "\t\n");
            in.skip(extraLength + csize);
            if ((flag & 8) != 0) {
                System.out.println("Data descriptor\tsignature\t" + String.format("%1$08X", in.readInt()) + "\tCRC-32\t" + in.readInt() + "\tc\t"
                        + in.readInt() + "\tu\t" + in.readInt());
            }
        }
        in.close();

    }

    public static String toHex(int value) {
        return String.format("%1$08X", value);
    }

    private static long dosToJavaTime(long dtime) {
        Date d = new Date((int) (((dtime >> 25) & 0x7f) + 80), (int) (((dtime >> 21) & 0x0f) - 1), (int) ((dtime >> 16) & 0x1f),
                (int) ((dtime >> 11) & 0x1f), (int) ((dtime >> 5) & 0x3f), (int) ((dtime << 1) & 0x3e));
        return d.getTime();
    }

    public static String formatTime(long time) {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(time));
    }

    public static void readWrite(InputStream in, OutputStream out, int len) throws IOException {
        byte[] b = new byte[1024];
        int count = 0;
        int tmp = in.read(b, 0, Math.min(b.length, len - count));
        while (true) {
            out.write(b, 0, tmp);
            count += tmp;
            if (count == len) break;
            tmp = in.read(b, 0, Math.min(b.length, len - count));
        }
    }
}
